package com.qkjia.srb.base.util;


import com.qkjia.common.exception.BusinessException;
import com.qkjia.common.result.ResponseEnum;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;

/**
 一个JWT由三部分组成：
 Header（头部） —— base64编码的Json字符串
 Payload（载荷） —— base64编码的Json字符串
 Signature（签名）—— 使用指定算法，通过Header和Payload加盐计算的字符串

 作者：vayci
 链接：https://www.jianshu.com/p/1ebfc1d78928
 来源：简书
 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
 */
public class JwtUtils {

    /**
     * 过期时间，毫秒，24小时  一般都是静态的
     */
    private static long tokenExpiration = 24*60*60*1000;
    /**
     * 秘钥
     */
    private static String tokenSignKey = "A1t2g3uigu123456";


    /**
     * 签名hash
     * @return
     */
    private static Key getKeyInstance(){
        // JSON Web 算法 规范中定义的标准 JWT 签名算法名称的类型安全表示。
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 将密钥字符串参数转换为字节数组。
        byte[] bytes = DatatypeConverter.parseBase64Binary(tokenSignKey);
        // signatureAlgorithm.getJcaName() 返回用于计算签名的 JCA 算法的名称。
        return new SecretKeySpec(bytes,signatureAlgorithm.getJcaName());
    }

    /**
     * 生产JWT
     * @param userId
     * @param userName
     * @return
     */
    public static String createToken(Long userId, String userName) {
        String token = Jwts.builder()
                .setSubject("SRB-USER")//令牌主题
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))//过期时间
                .claim("userId", userId)// 载荷：自定义信息
                .claim("userName", userName)// 载荷：自定义信息
                .signWith(SignatureAlgorithm.HS512, getKeyInstance())// 签名哈希
                .compressWith(CompressionCodecs.GZIP)//使用指定的CompressionCodec JWT 正文。
                .compact();//转换成字符串
        return token;
    }

    /**
     * 判断token是否有效
     * @param token
     * @return
     */
    public static boolean checkToken(String token) {
        if(StringUtils.isEmpty(token)) {
            return false;
        }
        try {
            // 获取序列化 JWS 字符串对象，里面可以拿到JWT
            Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * 获取载荷：自定义用户ID
     * @param token
     * @return
     */
    public static Long getUserId(String token) {
        Claims claims = getClaims(token);
        Integer userId = (Integer)claims.get("userId");
        return userId.longValue();
    }

    /**
     * 获取载荷：自定义用户名
     * @param token
     * @return
     */
    public static String getUserName(String token) {
        Claims claims = getClaims(token);
        return (String)claims.get("userName");
    }

    public static void removeToken(String token) {
        //jwttoken无需删除，客户端扔掉即可。
    }

    /**
     * 校验token并返回Claims
     * @param token
     * @return
     */
    private static Claims getClaims(String token) {
        if(StringUtils.isEmpty(token)) {
            // LOGIN_AUTH_ERROR(-211, "未登录"),
            throw new BusinessException(ResponseEnum.LOGIN_AUTH_ERROR);
        }
        try {
            // 获取序列化 JWS 字符串对象，里面可以拿到JWT
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
            //  返回 JWT 主体
            Claims claims = claimsJws.getBody();
            return claims;
        } catch (Exception e) {
            throw new BusinessException(ResponseEnum.LOGIN_AUTH_ERROR);
        }
    }
}

